package com.navy.list;

import java.util.Iterator;

public class SingleLinkedListWithHeader implements ListInterface {

    private Node head;
    private int size = 0;

    public SingleLinkedListWithHeader() {
        head = new Node(-1, null);
    }

    public class SingleLinkedListIterator implements Iterator<Integer> {
        private Node point;

        public SingleLinkedListIterator() {
            this.point = head.next;
        }

        @Override
        public boolean hasNext() {
            return point != null;
        }

        @Override
        public Integer next() {
            Integer value = point.value;
            point = point.next;
            return value;
        }

        @Override
        public void remove() {
        }
    }

    @Override
    public Iterator<Integer> iterator() {
        return new SingleLinkedListIterator();
    }

    @Override
    public boolean addFirst(Integer integer) {
        add(0, integer);
        return true;
    }

    @Override
    public void add(int index, Integer element) {
        checkAddRange(index);
        Node pre = findNode(index - 1);
        pre.next = new Node(element, pre.next);
        size++;
    }

    @Override
    public boolean addLast(Integer integer) {
        add(size, integer);
        return false;
    }

    @Override
    public Integer get(int index) {
        checkRemoveAndGetRange(index);
        Node point = head.next;
        int nowIndex = 0;
        while (point != null) {
            if (nowIndex == index) {
                return point.value;
            }
            point = point.next;
            nowIndex++;
        }
        return null;
    }

    public Node findNode(int index) {
        Node point = head;
        int nowIndex = -1;
        while (point != null) {
            if (nowIndex == index) {
                return point;
            }
            point = point.next;
            nowIndex++;
        }
        return null;
    }

    @Override
    public Integer remove(int index) {
        checkRemoveAndGetRange(index);
        Node pre = findNode(index - 1);
        Node removed = pre.next;
        pre.next = removed.next;
        size--;
        return removed.value;
    }

    @Override
    public Integer removeFirst() {
        if (size == 0) {
            throw new IllegalArgumentException("list is empty");
        }
        int value = head.next.value;
        head.next = head.next.next;
        size--;
        return value;
    }

    @Override
    public Integer removeLast() {
        return remove(size - 1);
    }

    @Override
    public int[] toArray() {
        int[] array = new int[size];
        Iterator<Integer> iterator = iterator();
        int index = 0;
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            if (value != null) {
                array[index++] = value;
            }
        }
        return array;
    }

    @Override
    public String toString() {
        Iterator<Integer> iterator = iterator();
        StringBuilder sb = new StringBuilder();
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            if (value == null) {
                sb.append(value);
            } else {
                sb.append(value).append("-->");
            }
        }
        return "SingleLinkedList{" +
                sb.toString() +
                '}';
    }

    static class Node {
        int value;
        Node next;

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

    private void checkRemoveAndGetRange(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("index is " + index + " right range is [0, " + (size - 1) + "]");
        }
    }

    private void checkAddRange(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is " + index + " right range is [0, " + size + "]");
        }
    }
}
